#include <iostream>
#include <sstream>
#include <QtGui>
#include <QWidget>
#include <PopupClientUI.hpp>
#include "PopupUtilities.hpp"
#include "PopupThreadTextWidget.hpp"
#include "PopupThreadWidget.hpp"
#include "PopupUsersManager.hpp"
#include "PopupGuiCore.hpp"
#include "PopupUsersDialog.hpp"
#include "PopupMessageDialog.hpp"
#include "PopupOSAL.hpp"

using namespace std;
using namespace utilities;
using namespace PopupUtils;
using namespace Popup;

static const char *c_messageFormat1 =
    "<table width=100% bgcolor='#FEFEF2'><tr><td width=48 align=center>"
    "%1</td><td><u><b>%2</b></u>&nbsp;<font size=2>[%3]</font>:%6%7%8%9</td>"
    "</tr></table>";
static const char *c_messageFormat2 =
    "<table width=100% bgcolor='#FEF6EF'><tr><td width=48 align=center>"
    "%1</td><td><u><b>%2</b></u>&nbsp;<font size=2>[%3]</font>:%4%5%6%7</td>"
    "</tr></table>";

//==============================================================================
// Construction/Destruction
//==============================================================================

PopupThreadWidget::PopupThreadWidget(QWidget *p_parent,
                                     const Popup::ThreadID & p_threadID,
                                     const Popup::UserList & p_attendants,
                                     const QString & p_threadTitle,
                                     bool p_isThreadTitleValid,
                                     const QString & p_text)
  : QWidget(p_parent), m_threadID(p_threadID),
    m_threadText(0), m_threadTitle(p_threadTitle),
    m_sendThreadTitle(p_isThreadTitleValid),
    m_selectedUserForPrivateMessage(-1), m_userProfileFrame(0),
    m_userProfileFrameShowUser(-1), m_contextMenu(m_threadText),
    currentMessageIndex(0)
{
  setupUi(this);

  // Create thread text widget (inherits QTextBrowser class)
  m_threadText = new PopupThreadTextWidget(this);
  QSizePolicy szpolicy(QSizePolicy(QSizePolicy::Expanding,
                                   QSizePolicy::Expanding));
  szpolicy.setHorizontalStretch(4);
  m_threadText->setSizePolicy(szpolicy);
  m_threadTextLayout->addWidget(m_threadText, 0, 0);
  m_threadTextLayout->addWidget(m_attendantsFrame, 0, 1);
  m_toggleAttendantsBtn->setChecked(false);
  slot_showAttendantsList(false);
  m_clearSelectionBtn->setVisible(false);

  // Setup document model and cursor
  document = new QTextDocument(m_threadText);
  m_threadText->setDocument(document);
  cursor = new QTextCursor(document);

  // Create context menu
  m_likeAction         = m_contextMenu.addAction(QIcon(":/images/popup_like.png"), tr("I like!"));
  m_dontLikeAction     = m_contextMenu.addAction(QIcon(":/images/popup_dislike.png"), tr("You suck!!"));
  m_pointFinesseAction = m_contextMenu.addAction(QIcon(":/images/popup_pointfinesse.png"), tr("Point finesse!"));
  m_fuckAction         = m_contextMenu.addAction(QIcon(":/images/popup_fuckyou20x20.png"), tr("Fuck sender"));
  m_likeAction->setIconVisibleInMenu(true);
  m_dontLikeAction->setIconVisibleInMenu(true);
  m_pointFinesseAction->setIconVisibleInMenu(true);
  m_fuckAction->setIconVisibleInMenu(true);

  m_action2ReactionMap[m_likeAction]          = POPUP_RATE_LIKE;
  m_action2ReactionMap[m_dontLikeAction]      = POPUP_RATE_DONTLIKE;
  m_action2ReactionMap[m_pointFinesseAction]  = POPUP_RATE_POETRY;
  m_action2ReactionMap[m_fuckAction]          = POPUP_RATE_FUCKYOU;
  m_reaction2ActionsMap[POPUP_RATE_LIKE]      = m_likeAction;
  m_reaction2ActionsMap[POPUP_RATE_DONTLIKE]  = m_dontLikeAction;
  m_reaction2ActionsMap[POPUP_RATE_POETRY]    = m_pointFinesseAction;
  m_reaction2ActionsMap[POPUP_RATE_FUCKYOU]   = m_fuckAction;

  PopupUsersManager::instance()->registerObserver(this);

  // Set reply all and close shortcuts
  QAction *_sendAction = new QAction(tr("&Send"), this);
  QList<QKeySequence> _sendShortcuts;
  _sendShortcuts << QKeySequence(Qt::CTRL + Qt::Key_Enter);
  _sendShortcuts << QKeySequence(Qt::CTRL + Qt::Key_Return);
  _sendAction->setShortcuts(_sendShortcuts);
  _sendAction->setShortcutContext(Qt::WidgetWithChildrenShortcut);
  addAction(_sendAction);
  connect(_sendAction, SIGNAL(triggered()), this, SLOT(slot_sendMessage()));

  connect(m_browseAttachedFileBtn, SIGNAL(clicked()), this, SLOT(slot_browseAttachment()));
  connect(m_sendBtn, SIGNAL(clicked()), this, SLOT(slot_sendMessage()));
  connect(m_threadText, SIGNAL(sourceChanged(const QUrl &)),
          this, SLOT(slot_onUrlClicked(const QUrl &)));
  connect(m_threadText, SIGNAL(highlighted(const QString &)),
          this, SLOT(slot_onMouseOverUrl(const QString &)));
  connect(m_toggleAttendantsBtn, SIGNAL(toggled(bool)),
          this, SLOT(slot_showAttendantsList(bool)));
  connect(m_attendantsList, SIGNAL(itemClicked(QListWidgetItem*)),
          this, SLOT(slot_enterPrivateMessageMode(QListWidgetItem*)));
  connect(m_clearSelectionBtn, SIGNAL(clicked()),
          this, SLOT(slot_exitPrivateMessageMode()));
  connect(m_addAttendantsBtn, SIGNAL(clicked()),
          this, SLOT(slot_addAttendants()));
  connect(&m_userProfileFrameShowTimer, SIGNAL(timeout()),
          this, SLOT(slot_showUserProfile()));

  const_collection_foreach(PopupSettings::instance()->customButtons(),
                           PopupCustomButtonList, _it)
  {
    PopupCustomQtButton *_btn = new PopupCustomQtButton(**_it);
    m_customButtonList.push_back(_btn);
    m_buttonsLayout->addWidget(_btn);
    connect(_btn, SIGNAL(clicked()), this, SLOT(slot_customButtonClicked()));
  }

  // Add attendants
  UserID _myID = getMyID();
  const_set_foreach(p_attendants, UserID, _attendant) {
    if (*_attendant != _myID) {
      addAttendant(*_attendant, true);
    }
  }

  m_threadText->setHtml(p_text);
}

PopupThreadWidget::~PopupThreadWidget()
{
  PopupUsersManager::instance()->unregisterObserver(this);
}

//==============================================================================
// Show functions
//==============================================================================

void PopupThreadWidget::slot_showAttendantsList(bool p_show)
{
  m_attendantsList->setVisible(p_show);
  m_addAttendantsBtn->setVisible(p_show);
  QSizePolicy szpolicy(QSizePolicy(QSizePolicy::Expanding,
                                         QSizePolicy::Expanding));
  if (p_show) {
    szpolicy.setHorizontalStretch(5);
  } else {
    szpolicy.setHorizontalStretch(50);
  }
  m_threadText->setSizePolicy(szpolicy);
}

void PopupThreadWidget::slot_onMouseOverUrl(const QString & p_url)
{
  if (m_userProfileFrameShowTimer.isActive()) {
    m_userProfileFrameShowTimer.stop();
  }

  // Parse URL
  QStringList list = p_url.split("|");
  if (list.at(0).compare("AVATAR") == 0) {
    bool _ok = false;
    UserID _senderID = (UserID) list.at(1).toULong(&_ok, 16);
    if (_ok) {
      m_userProfileFrameShowUser = _senderID;
      m_userProfileFrameShowTimer.start(1500);
    }
  }
}

void PopupThreadWidget::slot_showUserProfile()
{
  m_userProfileFrameShowTimer.stop();
  if (m_userProfileFrame == 0) {
    m_userProfileFrame = new PopupUserProfileFrame();
  }
  if (m_userProfileFrame->setup(m_userProfileFrameShowUser)) {
    m_userProfileFrame->move(QCursor::pos() - QPoint(15,15));
    m_userProfileFrame->setVisible(true);
  }
}

void PopupThreadWidget::slot_onUrlClicked(const QUrl & p_url)
{
  // Parse URL
  QString _text = p_url.toString();
  QStringList list = _text.split("|");

  if (list.at(0).compare("MSG") == 0) {
    bool _ok = false;
    MessageID _msgid = (MessageID) list.at(1).toULongLong(&_ok, 16);
    UserID _sender = (UserID) list.at(2).toULong(&_ok, 16);

    // Make sure we are able to find this message in our map (which won't
    // be the case in case this part of the text has been restored from
    // a saved thread
    Message2BlocknumberMap::iterator _itBlock =
        m_message2BlocknumberMap.find(_msgid);
    if (_itBlock == m_message2BlocknumberMap.end()) {
      showError("Cannot react on a message which had been\n"
                "restored from a saved session", this);
      return;
    }

    // Show the menu
    MsgReactionMask _reactionMask = (MsgReactionMask) POPUP_RATE_UNKNOWN;
    Message2ReactionsMap::iterator _itmask = m_message2ReactionsMap.find(_msgid);
    if (_itmask != m_message2ReactionsMap.end()) {
      _reactionMask = _itmask->second;
    }
    Reaction2ActionMap::iterator _it;
    for (_it = m_reaction2ActionsMap.begin(); _it != m_reaction2ActionsMap.end(); _it++) {
      bool enableAction = ((_reactionMask & _it->first) == 0);
      _it->second->setEnabled(enableAction);
    }
    QAction *_selectedAction = m_contextMenu.exec(QCursor::pos() - QPoint(15,15));

    // If user clicked and action let, send associated reaction message
    if (_selectedAction != 0) {

      UserRateItem _reactionType = m_action2ReactionMap[_selectedAction];

      // Update mask
      _reactionMask |= _reactionType;
      m_message2ReactionsMap[_msgid] = _reactionMask;

      UserList _targets;
      for (int _i = 0; _i < m_attendantsList->count(); _i++) {
        _targets.insert(m_attendantsList->item(_i)->
                        data(PopupGuiCore::POPUP_USER_ID).toUInt());
      }
      RateUserMessage _reaction(_reactionType, getMyID(), _msgid,
                                m_threadID, _sender, _targets, false);
      processMessageReaction(_reaction);
      emit signal_sendMessageReaction(&_reaction);
    }
  }
  else if (list.at(0).compare("MEDIA") == 0) {
    QString _path = list.at(1);
    // Image
    if (isSupportedImage(_path.toStdString().c_str())) {
      if (PopupSettings::instance()->useEmbeddedImageViewer()) {
        emit signal_showImage(_path, "");
      }
      else {
        openImage(_path.toStdString());
      }
    }
    // Other media
    else {
      openMedia(_path.toStdString());
    }
  }
  else if (list.at(0).compare("URL") == 0) {
    QString _url = list.at(1);
    openUrl(_url.toStdString());
  }
  else if (list.at(0).compare("AVATAR") == 0) {
    bool _ok = false;
    UserID _senderID = (UserID) list.at(1).toULong(&_ok, 16);
    if (_ok) {
      m_userProfileFrameShowUser = _senderID;
      m_userProfileFrameShowTimer.start(0);
    }
  }
}

void PopupThreadWidget::processMessageReaction(
    const RateUserMessage & p_reaction)
{
  QString _nameRSender = getNickname(p_reaction.rateSenderID).c_str();
  QString _nameMSender = getNickname(p_reaction.msgSenderID).c_str();
  QString _text = "";
  QString _img = "";
  bool _ok = true;

  Message2BlocknumberMap::iterator _it =
      m_message2BlocknumberMap.find(p_reaction.msgID);
  if (_it == m_message2BlocknumberMap.end()) {
    error("Strange!! Cannot find message!");
  }
  else
  {
    QTextCursor tmpCursor(document->findBlockByNumber(_it->second));
    tmpCursor.movePosition(QTextCursor::EndOfBlock);

    switch (p_reaction.rateItem) {
      case POPUP_RATE_LIKE:
        _text = tr("I like!");
        _img = "like";
        break;
      case POPUP_RATE_DONTLIKE:
        _text = tr("You suck!");
        _img = "dislike";
        break;
      case POPUP_RATE_POETRY:
        _text = tr("1 point finesse!");
        _img = "pointfinesse";
        break;
      case POPUP_RATE_FUCKYOU:
        _text = tr("Fuck you!");
        _img = "fuckyou20x20";
        break;
      default:
        _ok = false;
        break;
    }

    if (_ok) {
      QScrollBar *_vbar = m_threadText->verticalScrollBar();
      bool _scrolldown = (_vbar->sliderPosition() == _vbar->maximum());

      tmpCursor.insertHtml("<br>" + eventNotificationString(
          QString("[") + _nameRSender + " to " + _nameMSender + "] " + _text +
          " <img style='vertical-align:middle;'src=':/images/popup_"
          + _img + ".png'>", QColor("#444444")));

      if (_vbar->isEnabled() && _scrolldown) {
        m_threadText->verticalScrollBar()->triggerAction(QAbstractSlider::SliderToMaximum);
      }
    }
  }
}

bool PopupThreadWidget::doThreadTitleUpdate(const QString & p_title)
{
  // Our thread title is already valid => no update!
  //   OR
  // Given thread title is empty => no update!
  if ((m_sendThreadTitle == true) || (p_title.length() == 0))
  {
    return false;
  }
  // Otherwise update it (also save the fact that we can now
  // send it to other users!)
  else
  {
    m_threadTitle = p_title;
    m_sendThreadTitle = true;
    return true;
  }
}

QString PopupThreadWidget::eventNotificationString(const QString & p_notif,
    const QColor & p_textColor)
{
  return QString("<font size=2 color='%1'><i>%2</i></font>").
      arg(p_textColor.name(), p_notif);
}

void PopupThreadWidget::addAttendant(UserID p_userID, bool p_notify)
{
  bool _found = false;
  for (int _i = 0; _i < m_attendantsList->count(); _i++) {
    if (m_attendantsList->item(_i)->data(PopupGuiCore::POPUP_USER_ID).toUInt() == p_userID) {
      _found = true;
      break;
    }
  }
  if (!_found) {

    PopupUserExt _user;

    if (getUserInfo(_user, p_userID))
    {
      QListWidgetItem *_item = new QListWidgetItem(m_attendantsList);
      _item->setText(_user.getNickname().c_str());
      _item->setTextAlignment(Qt::AlignLeft);
      _item->setData(PopupGuiCore::POPUP_USER_ID,
                     QVariant((unsigned int) p_userID));
      if (_user.isAlive()) {
        _item->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled);
      } else {
        Qt::ItemFlags _defaultFlags = _item->flags();
        Qt::ItemFlags _flags = _defaultFlags & ~(Qt::ItemIsEnabled|Qt::ItemIsSelectable);
        _item->setFlags(_flags);
      }
      _item->setIcon(QIcon(_user.getAvatar().c_str()));
      if (p_notify) {
        m_threadText->append(eventNotificationString(QString("[<b>") +
                             _user.getNickname().c_str() +
                             "</b> joined in.]", QColor("#7fb9d7")));
      }
    }
    else
    {
      m_unresolvedUsers.insert(p_userID);
    }
  }
}

void PopupThreadWidget::userUpdated(const PopupUserExt* p_user,
                                         unsigned short p_updateMask,
                                         bool /* p_isNewUser */)
{
  if (p_updateMask & POPUP_USER_FIELD_HEALTH)
  {
    // Nice! This user is one of those we were not able to resolve!
    UserList::iterator _it = m_unresolvedUsers.find(p_user->getID());
    if (_it != m_unresolvedUsers.end())
    {
      m_unresolvedUsers.erase(_it);
      addAttendant(p_user->getID(), true);
    }
    else
    {
      QListWidgetItem *_useritem = 0;
      // Find user in list
      for (int _i = 0; _i < m_attendantsList->count(); _i++) {
        if (m_attendantsList->item(_i)->data(PopupGuiCore::POPUP_USER_ID).toUInt()  == p_user->getID()) {
          _useritem = m_attendantsList->item(_i);
          break;
        }
      }
      if (_useritem != 0)
      {
        // User connected
        if (p_user->isAlive())
        {
          Qt::ItemFlags _previousFlags = _useritem->flags();
          Qt::ItemFlags _newFlags = _previousFlags|Qt::ItemIsEnabled|Qt::ItemIsSelectable;
          _useritem->setFlags(_newFlags);
          m_threadText->append(eventNotificationString(QString("[<b>") +
                                                       p_user->getNickname().c_str() +
                                                       "</b> is back.]", QColor("#92d9a2")));
        }
        // User disconnected
        else
        {
          Qt::ItemFlags _previousFlags = _useritem->flags();
          Qt::ItemFlags _newFlags = _previousFlags & ~(Qt::ItemIsEnabled|Qt::ItemIsSelectable);
          _useritem->setFlags(_newFlags);
          m_threadText->append(eventNotificationString(QString("[<b>") +
                                                       p_user->getNickname().c_str() +
                                                       "</b> disconnected.]", QColor("#f45d5d")));
        }
      }
    }
  }
}

void PopupThreadWidget::slot_showMessage(const UserMessage *p_message)
{
  const char *_formatString = NULL;
  QString _privateMessageHeader = "";
  UserID _myID = getMyID();

  if (p_message->threadID == m_threadID)
  {
    PopupUserExt _sender;
    getUserInfo(_sender, p_message->senderID);
    QIcon _icon;
    _icon.addFile(QString::fromUtf8(_sender.getAvatar().c_str()));
    QSize _size = _icon.actualSize(QSize(48,48));

    // Private message?
    if ((m_attendantsList->count() > 1 ) && (p_message->targets.size() == 1))
    {
      QString _otherGuy;
      if (p_message->senderID == _myID) {
        _otherGuy = getNickname(*p_message->targets.begin()).c_str();
      } else {
        _otherGuy = getNickname(p_message->senderID).c_str();
      }
      _privateMessageHeader =
          QString("<font color='red'><b>[PRIVATE MESSAGE WITH <u><i>") +
            _otherGuy + "</i></u>]</b></font><br>";
    }

    // Prepare avatar string
    QString _avatar = QString("<a href='AVATAR|") +
        QString::number((ulong) p_message->senderID, 16) + "'>" +
        QString("<img src='%1' height='%2' width='%3'>").arg(
            _sender.getAvatar().c_str(),
            QString::number(_size.height()),
            QString::number(_size.width()));

    // Prepare attachment string
    QString _attachments = "";
    AttachmentList::const_iterator _it;
    int _maxImageWidth  = 300; // m_threadText->width()  / 2;
    int _maxImageHeight = 150; // m_threadText->height() / 2;

    for (_it = p_message->files.begin(); _it != p_message->files.end(); _it++) {
      QString _media = QString::fromUtf8(_it->c_str());
      QString _linkTxt = "[Media: " + _media + "]";

      // for images, we display a thumbnail instead of the symlink
      if (isSupportedImage(_media.toStdString().c_str()))
      {
        QImage *_image = new QImage(_media);
        if (!_image->isNull())
        {
          // This is the real image size
          int _imageWidth = _image->width();
          int _imageHeight = _image->height();
          // Update width according to max allowed size
          if (_imageWidth > _maxImageWidth)
          {
            _imageHeight = _imageHeight * _maxImageWidth / _imageWidth;
            _imageWidth = _maxImageWidth;
          }
          // Update height according to max allowed size
          if (_imageHeight > _maxImageHeight)
          {
            _imageWidth = _imageWidth * _maxImageHeight / _imageHeight;
            _imageHeight = _maxImageHeight;
          }
          // Create thumb image
          _linkTxt = "<img src='" + _media +
              "' width='" + QString::number(_imageWidth, 10) + "'" +
              "' height='" + QString::number(_imageHeight, 10) + "'>";
        }
        else
        {
          error("Failed to instantiate QImage %s", _media.toStdString().c_str());
        }
        delete _image;
      }

      _attachments += QString("<br><a href='MEDIA|") + _media + "'>" +
          _linkTxt + "</a>";
    }
    for (_it = p_message->URLs.begin(); _it != p_message->URLs.end(); _it++) {
      _attachments += QString("<br><a href='URL|") +
          QString::fromUtf8(_it->c_str()) + "'>[URL: " +
          QString::fromUtf8(_it->c_str()) + "]</a>";
    }

    QScrollBar *_vbar = m_threadText->verticalScrollBar();
    bool _scrolldown = (_vbar->sliderPosition() == _vbar->maximum());

    if ((currentMessageIndex % 2) == 0) {
      _formatString = c_messageFormat1;
    } else {
      _formatString = c_messageFormat2;
    }
    currentMessageIndex++;

    cursor->insertHtml(QString(_formatString).arg(
        // Avatar (1)
        _avatar,
        // Nickname (2)
        _sender.getNickname().c_str(),
        // Date (3)
        QDateTime::currentDateTime().toString("dd/MM-hh'h'mm:ss"),
        // Menu button (4)
        (p_message->senderID == getMyID()? "<br>" :
            "&nbsp;&nbsp;<a href='MSG|" +
            QString::number((qulonglong) p_message->msgID, 16) + "|" +
            QString::number((ulong) p_message->senderID, 16) + "'>" +
            "<img src=':/images/popup_menu.png'></a><br>"),
        // Private message header (5)
        _privateMessageHeader,
        // Message text (6)
        QString::fromUtf8(p_message->text.c_str()).replace("\n", "<br>"),
        // Attachments (7)
        _attachments));

    // Save the number of the block where the message will be written
    m_message2BlocknumberMap[p_message->msgID] = cursor->block().blockNumber();

    if (_vbar->isEnabled() && _scrolldown) {
      m_threadText->verticalScrollBar()->triggerAction(QAbstractSlider::SliderToMaximum);
    }
  }
}

//==============================================================================
// Send functions
//==============================================================================

void PopupThreadWidget::slot_sendMessage()
{
  UserMessage _msg;
  
  // Nothing to send => nothing to do!
  if (m_sendText->toPlainText().isEmpty() && m_attachedEdit->text().isEmpty()) {
    return;
  }

  _msg.threadID = m_threadID;

  _msg.text = (PopupSettings::instance()->customFontEnabled()?
      // Use user custom font setup?...
      PopupSettings::instance()->customFontPrefix().toStdString() +
      m_sendText->toPlainText().toStdString() +
      PopupSettings::instance()->customFontSuffix().toStdString() :
      // ... Or use default font
      m_sendText->toPlainText().toStdString());

  if (m_sendThreadTitle)
  {
    _msg.title = m_threadTitle.toStdString().c_str();
  }

  // Private message
  if (m_selectedUserForPrivateMessage != (UserID) -1) {
    _msg.targets.insert(m_selectedUserForPrivateMessage);
  }
  // Or everybody in the list
  else {
    QList<QListWidgetItem *> _sels = m_attendantsList->selectedItems();
    for (int _i = 0; _i < m_attendantsList->count(); _i++) {
      _msg.targets.insert(m_attendantsList->item(_i)->
                             data(PopupGuiCore::POPUP_USER_ID).toUInt());
    }
  }

  // Set attached file if set
  bool _mediaFailure = false;
  if (m_attachedEdit->text().length() > 0)
  {
    string _thing(m_attachedEdit->text().toUtf8().data());
    if (QFile(m_attachedEdit->text()).exists())
    {
      if (!ftest(_thing)) {
        showError(QString("Ooops! Failed to open file ") + m_attachedEdit->text() + ".\n");
        _mediaFailure = true;
      } else {
        _msg.files.push_back(m_attachedEdit->text().toUtf8().data());
      }
    } else
    {
      _msg.URLs.push_back(m_attachedEdit->text().toUtf8().data());
    }
  }

  if (_mediaFailure == false) {

    emit(signal_sendMessage(&_msg));
    // Clear controls
    m_sendText->clear();
    m_attachedEdit->clear();
  }
}
//----------------------------------------------------------

void PopupThreadWidget::slot_customButtonClicked()
{
  // Get a pointer on the clicked button
  PopupCustomQtButton *_sender = (PopupCustomQtButton*) QObject::sender();
  m_sendText->setPlainText(_sender->msgText());
  m_attachedEdit->setText(_sender->mediaUrl());
  slot_sendMessage();
}
//----------------------------------------------------------

void PopupThreadWidget::slot_enterPrivateMessageMode(QListWidgetItem *p_itemClicked)
{
  UserID _userID = p_itemClicked->data(PopupGuiCore::POPUP_USER_ID).toUInt();

  // A user was already selected... and has been re-clicked
  if (m_selectedUserForPrivateMessage == _userID)
  {
    slot_exitPrivateMessageMode();
  }
  // Otherwise, we select the new user
  else if (isAlive(_userID))
  {
    m_selectedUserForPrivateMessage = _userID;
    QString _nickname = getNickname(_userID).c_str();
    m_sendTextBox->setTitle(tr("Private message with") + " " + _nickname + "...");
    m_sendTextBox->setStyleSheet("color: #FF0000;font-weight:500;");
    m_clearSelectionBtn->setVisible(true);
    m_sendText->setFocus();
  }
}
//----------------------------------------------------------

void PopupThreadWidget::slot_exitPrivateMessageMode()
{
  m_clearSelectionBtn->setVisible(false);
  m_selectedUserForPrivateMessage = -1;
  m_attendantsList->clearSelection();
  m_sendTextBox->setTitle(tr("Write..."));
  m_sendTextBox->setStyleSheet("");
  m_sendText->setFocus();
}
//----------------------------------------------------------

void PopupThreadWidget::slot_browseAttachment()
{
  static QString _lastFileSelected = "";
  selectFileToTextEdit(m_attachedEdit, this,
                       tr("Select file to attach..."),
                       tr("All Files (*);;Image Files (*.jpg *.png *gif);;"
                           "Video Files(*.mpg *.mp4 *.avi *.wmv"),
                           _lastFileSelected);
  if (m_attachedEdit->text().length() > 0)
  {
    _lastFileSelected = m_attachedEdit->text();
  }
}

void PopupThreadWidget::slot_addAttendants()
{
  // Build list of current attendants
  UserList _currentAttendants;
  for (int _i = 0; _i < m_attendantsList->count(); _i++) {
    _currentAttendants.insert(m_attendantsList->item(_i)->
                       data(PopupGuiCore::POPUP_USER_ID).toUInt());
  }

  // Show dialog
  PopupUsersDialog _dlg(this, _currentAttendants);
  ThreadInvitation _invitation(m_threadID, m_threadTitle.toUtf8().data());

  if (_dlg.exec() == QDialog::Accepted) {
    UserList _newAttendants;
    _dlg.getSelectedUsers(_newAttendants);
    for (UserList::iterator _it = _newAttendants.begin();
        _it != _newAttendants.end(); _it++) {
      _invitation.invitedUsers.insert(*_it);
    }
  }

  if (_invitation.invitedUsers.size() > 0) {

    // CC all users which are already in the thread
    QList<QListWidgetItem *> _sels = m_attendantsList->selectedItems();
    for (int _i = 0; _i < m_attendantsList->count(); _i++) {
      _invitation.cc.insert(m_attendantsList->item(_i)->
          data(PopupGuiCore::POPUP_USER_ID).toUInt());
    }
    _invitation.cc.insert(getMyID());

    // I am also the one who invited those persons
    _invitation.inviter = getMyID();

    // Send invitation
    emit signal_sendInvitation(&_invitation);
  }
}

void PopupThreadWidget::processInvitation(
    const ThreadInvitation & p_invitation, bool p_isCc)
{
  if (p_isCc) {
    const_set_foreach(p_invitation.invitedUsers, UserID, _attendant) {
      addAttendant(*_attendant, true);
    }
  }
  else
  {
    UserList::iterator _it;
    m_threadText->append(eventNotificationString(QString("[<b>") +
                          getNickname(p_invitation.inviter).c_str() +
                          "</b> invited you to this thread.]",
                          QColor("#7fb9d7")));
    addAttendant(p_invitation.inviter, false);
    const_set_foreach(p_invitation.cc, UserID, _attendant) {
      if (*_attendant != p_invitation.inviter) {
        addAttendant(*_attendant, true);
      }
    }
  }
}

//=============================================================================
// Custom buttons update
//=============================================================================

void PopupThreadWidget::slot_applyNewSettings()
{
  PopupSettings *_settings = PopupSettings::instance();

  // Iterate on each custom button currently in the widget
  PopupCustomButtonList::iterator _itCurrent = m_customButtonList.begin();
  while (_itCurrent != m_customButtonList.end())
  {
    // This is the current button
    PopupCustomQtButton *_btn = (PopupCustomQtButton*) *_itCurrent;

    // Try to find it in the reference list
    PopupCustomButton *_ref = _settings->customButton((*_itCurrent)->name());

    // Not found! Let's delete it!
    if (_ref == 0)
    {
      m_buttonsLayout->removeWidget(_btn);
      delete _btn;
      _itCurrent = m_customButtonList.erase(_itCurrent);
    }
    // Otherwise, let's update it
    else
    {
      _btn->setup(*_ref);
      _itCurrent++;
    }
  }

  // Then, add new buttons...
  //
  // For each button defined in the settings
  const_collection_foreach(_settings->customButtons(), PopupCustomButtonList, _itRef)
  {
    // This is the button
    PopupCustomButton *_refBtn = *_itRef;

    // Try to find it in the widget buttons list
    bool _found = false;
    collection_foreach(m_customButtonList, PopupCustomButtonList, _itCurrent)
    {
      if ((*_itCurrent)->name() == _refBtn->name()) {
        _found = true;
        break;
      }
    }

    // If not found, add it
    if (_found == false)
    {
      PopupCustomQtButton *_newBtn = new PopupCustomQtButton(*_refBtn);
      m_customButtonList.push_back(_newBtn);
      m_buttonsLayout->addWidget(_newBtn);
      connect(_newBtn, SIGNAL(clicked()),
              this, SLOT(slot_customButtonClicked()));
    }
  }
}

const Popup::ThreadID & PopupThreadWidget::getID() const
{
  return m_threadID;
}

const QString & PopupThreadWidget::getTitle() const
{
  return m_threadTitle;
}

QStringList PopupThreadWidget::getUsers() const
{
  QStringList _users;
  for (int _i = 0; _i < m_attendantsList->count(); _i++) {
    _users << QString::number(m_attendantsList->item(_i)->data(
        PopupGuiCore::POPUP_USER_ID).toUInt(), 16);
  }
  return _users;
}

QString PopupThreadWidget::getText() const
{
  return m_threadText->toHtml();
}
